#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define CONTROL_INDEX	0x00
#define CONTROL_LENGTH  0x0a
#define CONFIG_INDEX	0x0b
#define CONFIG_LENGTH	0x72-0x0b
#define DATA_INDEX	0x78 //
#define DATA_LENGTH	0xdf-0x78

#define	ESC_KEY		0x1b

char *buf_write = NULL;
char *buf_read = NULL;

static int getch(void)
{
	struct termios oldt,newt;
	int ch;

	if (!isatty(STDIN_FILENO)) {
		fprintf(stderr, "this problem should be run at a terminal\n");
		exit(1);
	}
	// save terminal setting
	if(tcgetattr(STDIN_FILENO, &oldt) < 0) {
		perror("save the terminal setting");
		exit(1);
	}

	// set terminal as need
	newt = oldt;
	newt.c_lflag &= ~( ICANON | ECHO );
	if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) {
		perror("set terminal");
		exit(1);
	}

	ch = getchar();

	// restore termial setting
	if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) {
		perror("restore the termial setting");
		exit(1);
	}
	return ch;
}

static int fd = -1;
//static void close_buzzer(void);
static void open_ts(void)
{
	fd = open("/dev/zforcedebug", 0);
	if (fd < 0) {
		perror("open zforcedebug device");
		exit(1);
	}
	printf("open sucess\n");
	// any function exit call will stop the buzzer
	//atexit(close_buzzer);
}
/*
static void close_buzzer(void)
{
	if (fd >= 0) {
		ioctl(fd, PWM_IOCTL_STOP);
		if (ioctl(fd, 2) < 0) {
			perror("ioctl 2:");
		}
		close(fd);
		fd = -1;
	}
}

static void set_buzzer_freq(int freq)
{
	// this IOCTL command is the key to set frequency
	int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, freq);
	if(ret < 0) {
		perror("set the frequency of the buzzer");
		exit(1);
	}
}
static void stop_buzzer(void)
{
	int ret = ioctl(fd, PWM_IOCTL_STOP);
	if(ret < 0) {
		perror("stop the buzzer");
		exit(1);
	}
	if (ioctl(fd, 2) < 0) {
		perror("ioctl 2:");
	}
}
*/



static void print_func(void)
{
	printf("number:       funcion:	\n");
	printf("        0,    open device	\n");
	printf("        1,    close device	\n");
	printf("        2,    print control registers \n");
	printf("        3,    print configuration registers \n");
	printf("        4,    print data registers \n");
	printf("        5,    single scanning\n");
	printf("        6,    All scanning\n");
	printf("        7,    read registers\n");
	printf("        8,    write registers \n");
	printf("        9,    initialise configuration\n");
	printf("        a,    start scanning \n");
	printf("        b,    stop scanning \n");
	printf("        c,    \n");
	printf("        z,    exit .....\n");

	//printf("%10d,function 0\n",)
	//printf("%10d,function 1\n",)
	//printf("number:  ,funcion:\n")
}

unsigned int get_number()
{
	int flag,value;
	flag = 0;
	do
	{
		scanf("%d",&value);
		if(value > 231)
		{
			flag =1;
			printf("input invalid\n");
			printf("input data again:");
		}
		else
			flag = 0;
	}while(flag);
	
	return value;

}

static char read_registers(char index, char length)
{
	int value = 0;
	int i;
	value = index *1000 + length;
	ioctl(fd,3,value);
	buf_read = malloc(length);
	if(buf_read == NULL)
		return -1;
	value = read(fd,buf_read,length);
	for (i=0;i<length;i++)
		printf("offset:%3d ,value: 0x%x\n",index + i,*(buf_read + i));

	free(buf_read);
	return 0;

}


static char read_any_register()
{
	int offset,length,value;
	int i;
	printf("input the offset register (the value less than 231):");
	offset = get_number();
	printf("offset:%d\n",offset);
	printf("input the length (the value less than 231):");

	length = get_number();
	printf("length:%d\n",length);

	if(offset + length > 231)
	{
		printf("offset + length > 231\n invalid input\n");
		return 1;
	}
	value = offset*1000 + length;
	ioctl(fd,3,value);
	buf_read = malloc(length);
	if(buf_read == NULL)
		return -1;
	value = read(fd,buf_read,length);
	for (i=0;i<length;i++)
		printf("offset: %3d,value: 0x%x\n",offset + i,*(buf_read + i));

	free(buf_read);
	return 0;
}

int main(int argc, char **argv)
{
	int key = 0;
	
	open_ts();

	printf( "\nZFORCE TEST ( TS Control )\n" );
	//printf( "Press +/- to increase/reduce the frequency of the BUZZER\n" ) ;
	//printf( "Press 'ESC' key to Exit this program\n\n" );
	//memset(buf_read,0,128);
	//memset(buf_write,0,128);
	
	
	while( 1 )
	{
		//set_buzzer_freq(freq);
		//printf( "\tFreq = %d\n", freq );
		if(key != 10)
		print_func();
		printf("select number:\n\n\n");
		key = getch();
		if(key != 10)
		{
			printf("you input is ");
			printf("%c\n",key);
		}

		switch(key) {
		case '0':
			printf("open device .....\n");
			ioctl(fd,0,0);
			break;
		case '1':
			printf("close device ....\n");
			ioctl(fd,1,0);
			break;
		case '2': //read config registers
			printf("print control registers ....\n\n");
			read_registers(CONTROL_INDEX, CONTROL_LENGTH);
			//ioctl(fd,3,0);
			break;
		case '3':
			printf("print configuration registers ....\n\n");
			read_registers(CONFIG_INDEX, CONFIG_LENGTH);
			//ioctl(fd,3,0);
			break;
		case '4':
			printf("print register ....\n\n");
			read_registers(DATA_INDEX, DATA_LENGTH);
			//ioctl(fd,3,0);
			break;
		case '5': //single scanning
			printf("single scanning ....\n\n");
			ioctl(fd,4,0);
			break;
		case '6': //single scanning
			printf("all scanning ....\n\n");
			ioctl(fd,5,0);
			break;
		case '7': //single scanning
			printf("read register ....\n\n");
			read_any_register();
			break;
		case '8': //single scanning
			printf("write register ....\n\n");
			//ioctl(fd,4,0);
			break;
		case '9': //single scanning
			printf("Initialise configuration ....\n\n");
			ioctl(fd,7,0);
			break;
		case 'a': //single scanning
			printf("start scanning ....\n\n");
			ioctl(fd,8,0);
			break;
		case 'b': //single scanning
			printf("stop scanning ....\n\n");
			ioctl(fd,9,0);
			break;

		case 'h':
			print_func();
			break;

		case 'z':
		case EOF:
			//stop_buzzer();
			exit(0);

		default:
			break;
		}
	}
}



